# -*- coding: utf-8 -*-
# @Author: bao
# @Date:   2017-02-17 11:20:24
# @Last Modified by:   bao
# @Last Modified time: 2017-05-15 10:30:26

from gen_topo_fully import *
from datetime import datetime


class gen_topo_ovs(gen_topo_fully):
    """
	blocking circuit switch
	"""

    def __init__(self):
        gen_topo_fully.__init__(self)

    def _transform(self, wl_graph, tf_graph, degree, row_size, base_len):
        '''
		Generate new topology based on multi max_weight_matching (directed bipartite graph)
		node (bp_src, bipartite=0, degree=0)
		node (bp_dst, bipartite=0, degree=0)
		edge (src, dst, 'weight')
		'''
        # print "_transform_ovs"
        remain_edges = []
        temp_graph = tf_graph.copy()
        while temp_graph.edges():
            match = nx.max_weight_matching(temp_graph, maxcardinality=False)
            # print match
            for src in match:
                dst = match[src]
                if src <= base_len:
                    # print src, dst, temp_graph[src][dst]['weight']
                    (src_axis_x, src_axis_y) = get_cd(src, row_size)
                    (dst_axis_x, dst_axis_y) = get_cd(dst - base_len, row_size)
                    (Is_same_axis, cp_x, cp_y) = get_cp((src_axis_x, src_axis_y), (dst_axis_x, dst_axis_y), row_size,
                                                        base_len)

                    traffic_weight = get_weight(temp_graph[src][dst]['weight'])

                    if Is_same_axis:
                        max_degree = max(wl_graph.node[src]['degree'], wl_graph.node[dst]['degree'])
                        if max_degree < degree:
                            wl_max = degree - max_degree
                            wl_num = min(traffic_weight, wl_max)
                            wl_graph.node[src]['degree'] += wl_num
                            wl_graph.node[dst]['degree'] += wl_num
                            if (src, dst) not in wl_graph.edges():
                                wl_graph.add_edge(src, dst, weight=wl_num)
                            else:
                                wl_graph.edge[src][dst]['weight'] += wl_num
                        else:
                            remain_edges.append((src, dst))
                    else:
                        max_degree_x = max(wl_graph.node[src]['degree'], wl_graph.node[dst]['degree'],
                                           wl_graph.node[cp_x]['degree'],
                                           wl_graph.node[cp_x - base_len]['degree'])  # Indegree and Outdegree
                        max_degree_y = max(wl_graph.node[src]['degree'], wl_graph.node[dst]['degree'],
                                           wl_graph.node[cp_y]['degree'],
                                           wl_graph.node[cp_y - base_len]['degree'])  # Indegree and Outdegree
                        if max_degree_x > max_degree_y:
                            cp = cp_y
                            max_degree = max_degree_y
                        else:
                            cp = cp_x
                            max_degree = max_degree_x

                        if max_degree < degree:
                            wl_max = degree - max_degree
                            wl_num = min(traffic_weight, wl_max)

                            if (src, cp) not in wl_graph.edges():
                                wl_graph.add_edge(src, cp, weight=wl_num)
                            else:
                                wl_graph.edge[src][cp]['weight'] += wl_num

                            if (cp - base_len, dst) not in wl_graph.edges():
                                wl_graph.add_edge(cp - base_len, dst, weight=wl_num)
                            else:
                                wl_graph.edge[cp - base_len][dst]['weight'] += wl_num

                            wl_graph.node[src]['degree'] += wl_num
                            wl_graph.node[dst]['degree'] += wl_num
                            wl_graph.node[cp]['degree'] += wl_num
                            wl_graph.node[cp - base_len]['degree'] += wl_num
                        else:
                            remain_edges.append((src, dst))
                    temp_graph.remove_edge(src, dst)
